package com.rongji.dfish.demo.editor.service.uiadaptor;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import com.rongji.dfish.base.Utils;
import com.rongji.dfish.base.util.BeanUtil;
import com.rongji.dfish.ui.AbstractWidget;
import com.rongji.dfish.ui.Command;
import com.rongji.dfish.ui.Layout;
import com.rongji.dfish.ui.PubHolder;
import com.rongji.dfish.ui.Widget;
import com.rongji.dfish.ui.command.CommandContainer;
import com.rongji.dfish.ui.command.ConfirmCommand;
import com.rongji.dfish.ui.command.DialogCommand;
import com.rongji.dfish.ui.command.MenuCommand;
import com.rongji.dfish.ui.command.ReplaceCommand;
import com.rongji.dfish.ui.form.AbstractBox;
import com.rongji.dfish.ui.form.AbstractBoxgroup;
import com.rongji.dfish.ui.form.AbstractUpload;
import com.rongji.dfish.ui.form.Checkbox;
import com.rongji.dfish.ui.form.Checkboxgroup;
import com.rongji.dfish.ui.form.Combobox;
import com.rongji.dfish.ui.form.ComboboxOption;
import com.rongji.dfish.ui.form.Hidden;
import com.rongji.dfish.ui.form.Period;
import com.rongji.dfish.ui.form.Pickbox;
import com.rongji.dfish.ui.form.Radio;
import com.rongji.dfish.ui.form.Radiogroup;
import com.rongji.dfish.ui.form.UploadButton;
import com.rongji.dfish.ui.form.UploadItem;
import com.rongji.dfish.ui.form.Validatable;
import com.rongji.dfish.ui.form.Validate;
import com.rongji.dfish.ui.form.ValueButton;
import com.rongji.dfish.ui.helper.FlexGrid;
import com.rongji.dfish.ui.helper.FormPanel;
import com.rongji.dfish.ui.helper.GridLayoutFormPanel;
import com.rongji.dfish.ui.helper.GridPanel;
import com.rongji.dfish.ui.helper.HorizontalGroup;
import com.rongji.dfish.ui.helper.Label;
import com.rongji.dfish.ui.helper.StackPanel;
import com.rongji.dfish.ui.helper.TabPanel;
import com.rongji.dfish.ui.helper.VerticalGroup;
import com.rongji.dfish.ui.json.ClassJsonBuilder;
import com.rongji.dfish.ui.json.J;
import com.rongji.dfish.ui.json.JsonBuilder;
import com.rongji.dfish.ui.json.JsonBuilderProperGetter;
import com.rongji.dfish.ui.layout.AlbumLayout;
import com.rongji.dfish.ui.layout.ButtonBar;
import com.rongji.dfish.ui.layout.FieldsetLayout;
import com.rongji.dfish.ui.layout.GridLayout;
import com.rongji.dfish.ui.layout.HorizontalLayout;
import com.rongji.dfish.ui.layout.VerticalLayout;
import com.rongji.dfish.ui.layout.View;
import com.rongji.dfish.ui.layout.grid.AbstractTd;
import com.rongji.dfish.ui.layout.grid.GridColumn;
import com.rongji.dfish.ui.layout.grid.GridLeaf;
import com.rongji.dfish.ui.layout.grid.JsonGridLayout;
import com.rongji.dfish.ui.layout.grid.JsonTd;
import com.rongji.dfish.ui.layout.grid.JsonThead;
import com.rongji.dfish.ui.layout.grid.JsonTr;
import com.rongji.dfish.ui.layout.grid.Thead;
import com.rongji.dfish.ui.layout.grid.Tr;
import com.rongji.dfish.ui.plugin.echarts.EChartsPanel;
import com.rongji.dfish.ui.widget.Button;
import com.rongji.dfish.ui.widget.CalendarCss;
import com.rongji.dfish.ui.widget.CalendarItem;
import com.rongji.dfish.ui.widget.CalendarPanel;
import com.rongji.dfish.ui.widget.DialogTemplate;
import com.rongji.dfish.ui.widget.Img;
import com.rongji.dfish.ui.widget.Leaf;
import com.rongji.dfish.ui.widget.Progress;
import com.rongji.dfish.ui.widget.Split;
import com.rongji.dfish.ui.widget.SubmitButton;
import com.rongji.dfish.ui.widget.TemplateTitle;
import com.rongji.dfish.ui.widget.TemplateView;
import com.rongji.dfish.ui.widget.TreePanel;

/**
 * 定义组件之间的关系。
 * 这个类负责定义组件之间的容纳关系。
 * @author DFish Team
 *
 */
public class ComponentRelation {
	ComponentRelation(){	}
	private HashMap<String,List<Information>> subTypeMap=new HashMap<String,List<Information>>();
	private HashMap<String,Map<String,List<Information>>> specialTypeMap=new HashMap<String,Map<String,List<Information>>>();
	private HashMap<String,Map<String,List<Information>>> otherTypeMap=new HashMap<String,Map<String,List<Information>>>();
	
	/**
	 * 组件之间的关系的信息存放Bean
	 * @author DFish Team
	 *
	 */
	public static class Information{
		private String parentType;
		private String subType;
		private String addMethod;
		private List<PropertyDefine> appendingProperies;
		private boolean single;
		
		/**
		 * 父组件类型，一般来说也就是当前对象，不需要关注
		 * @return String
		 */
		public String getParentType() {
			return parentType;
		}
		/**
		 * 父组件类型，一般来说也就是当前对象，不需要关注
		 * @param parentType
		 */
		public void setParentType(String parentType) {
			this.parentType = parentType;
		}
		/**
		 * 可以增加的子节点的类型。
		 * @return String
		 */
		public String getSubType() {
			return subType;
		}
		/**
		 * 可以增加的子节点的类型。
		 * @param subType
		 */
		public void setSubType(String subType) {
			this.subType = subType;
		}
		/**
		 * 增加子节点的方法名
		 * @return String
		 */
		public String getAddMethod() {
			return addMethod;
		}
		/**
		 * 增加子节点的方法名
		 * @param addMethod
		 */
		public void setAddMethod(String addMethod) {
			this.addMethod = addMethod;
		}
		/**
		 * 增加该子节点的时候，需要追加的属性，比如说将Command设置到View中去需要制定这个Command的Id
		 * 那就是一个参数，这个参数名字叫id类型是字符型，必填为真，默认值没有
		 * 而部分子节点的增加不需要任何追加属性，直接调用add方法
		 * @return List
		 */
		public List<PropertyDefine> getAppendingProperies() {
			return appendingProperies;
		}
		/**
		 * 增加该子节点的时候，需要追加的属性，比如说将Command设置到View中去需要制定这个Command的Id
		 * 那就是一个参数，这个参数名字叫id类型是字符型，必填为真，默认值没有
		 * 而部分子节点的增加不需要任何追加属性，直接调用add方法
		 * @param appendingProperies
		 */
		public void setAppendingProperies(List<PropertyDefine> appendingProperies) {
			this.appendingProperies = appendingProperies;
		}
		/**
		 * 是否是唯一的 一般来说 &lt;pub&gt;类的特殊节点都是唯一的，但只判定同名唯一。即pub设置过了
		 * 但还可以设置combofild可以设置thead。
		 * 而普通的节点唯一的话。则可能是全局唯一。比如view.setNode(VerticalLayout xxx)了以后。
		 * 就不允许增加其他类似的唯一节点了。但还可以增加Command
		 * 
		 * @return boolean
		 */
		public boolean isSingle() {
			return single;
		}
		/**
		 * 是否是唯一的 一般来说 &lt;pub&gt;类的特殊节点都是唯一的，但只判定同名唯一。即pub设置过了
		 * 但还可以设置combofild可以设置thead。
		 * 而普通的节点唯一的话。则可能是全局唯一。比如view.setNode(VerticalLayout xxx)了以后。
		 * 就不允许增加其他类似的唯一节点了。但还可以增加Command
		 * @param single
		 */
		public void setSingle(boolean single) {
			this.single = single;
		}
		
	}

	
	/**
	 * 初始化组件间的关系。
	 * 两两判定组件是否存在容纳关系，并将容纳关系，以及细节参数(Infomation)存在MAP中
	 * 这里分为两个Map
	 * 一个是一般的容纳关系。一个是特殊的容纳关系
	 * 一般容纳关系，主要确定两个参数是否容纳，他们是否有唯一容纳的限制，加入父节点的时候是否要追加属性。
	 * 特殊的容纳关系一般是指 默认值，表头，特定的绑定字段。这些容纳关系，是唯一的，不可以设定ID。
	 * 通常追加到父节点中的方法也是特殊的。
	 * 2016-09-19
	 * 增加第三种容纳关系，一般用方括号标识
	 * 主要标识他们是另一种添加方式，比如ComboxGroup的add方法主要是其nodes属性，
	 * 而它可以容纳targets这时候就要用【target】来标识，调用的方法也是addTarget
	 * @param compInfo
	 */
	void init(final ComponentInfo compInfo){
		Map<String, Class<?>> adaptorClass =compInfo.adaptorClass;
		for(Map.Entry<String, Class<?>> entry:adaptorClass.entrySet()){
			for(Map.Entry<String, Class<?>> subEntry:adaptorClass.entrySet()){
				Information info=acceptInfo(entry.getKey(), entry.getValue(),subEntry.getKey(),subEntry.getValue());
				if(info!=null){
					List<Information> acc=subTypeMap.get(entry.getKey());
					if(acc==null){
						acc=new ArrayList<Information>();
						subTypeMap.put(entry.getKey(), acc);
					}
					acc.add(info);
				}
			}
		}
		//排序
		for(Map.Entry<String, Class<?>> entry:adaptorClass.entrySet()){
			List<Information> acc=subTypeMap.get(entry.getKey());
			if(acc==null){continue;}
			Collections.sort(acc,new Comparator<Information>(){
				@Override
				public int compare(Information o1, Information o2) {
					String type1=o1.getSubType();
					String type2=o2.getSubType();
					int order1=compInfo.getTypeSortOrder(type1);
					int order2=compInfo.getTypeSortOrder(type2);
					return order1-order2;
				}
			});
		}
		//增加特殊属性的初始化
		for(Map.Entry<String, Class<?>> entry:adaptorClass.entrySet()){
			Class<?> clz=entry.getValue();
		Map<String,List<Information>> result=new LinkedHashMap<String,List<Information>>();
		if(PubHolder.class.isAssignableFrom(clz)){
			String subtype="Html";
			JsonBuilder b = J.get(clz);
			ClassJsonBuilder cjb = (ClassJsonBuilder) b;
			Class<?> theHolder=null;
			for (JsonBuilderProperGetter getter : cjb.getMethods()) {
				if(getter.getPropName().equals("pub")){
					if(theHolder==null){
						theHolder=getter.getGetterMethod().getDeclaringClass();
						subtype= BeanUtil.getClassShortName(getter.getGetterMethod().getReturnType().getName());
					}else{
						Class<?> newHolder=getter.getGetterMethod().getDeclaringClass();
						if(theHolder.isAssignableFrom(newHolder)){
							theHolder=newHolder;
							subtype= BeanUtil.getClassShortName(getter.getGetterMethod().getReturnType().getName());
						}
					}				
				}
			}
			Information si=new Information();
			si.setParentType(entry.getKey());
			si.setSubType(subtype);
			si.setAddMethod("setPub");
			si.setSingle(true);
			result.put("pub", Arrays.asList(si));
		}
		if(GridLayout.class==clz){
			Information si=new Information();
			si.setParentType(entry.getKey());
			si.setSubType("Thead");
			si.setAddMethod("setThead");
			si.setSingle(true);
			result.put("thead", Arrays.asList(si));
		}
		
		if(CalendarPanel.class==clz){
			List<Information> subs=new ArrayList<Information>();
			for(Map.Entry<String, Class<?>> subEntry:adaptorClass.entrySet()){
				if(subEntry.getValue()==CalendarCss.class){
					Information si=new Information();
					si.setParentType(entry.getKey());
					si.setSubType(subEntry.getKey());
					si.setAddMethod("addCss");
					si.setSingle(true);
					subs.add(si);
				}
			}
			result.put("css", subs);
		}
		
		if(Combobox.class==clz){
			List<Information> subs=new ArrayList<Information>();
			for(Map.Entry<String, Class<?>> subEntry:adaptorClass.entrySet()){
				if(ComboboxOption.class==subEntry.getValue()){
					Information si=new Information();
					si.setParentType(entry.getKey());
					si.setSubType(subEntry.getKey());
					si.setAddMethod("setPub");
					subs.add(si);
				}
			}
			result.put("pub", subs);
		}

		if(Pickbox.class==clz){
			List<Information> subs=new ArrayList<Information>();
			for(Map.Entry<String, Class<?>> subEntry:adaptorClass.entrySet()){
				if(DialogCommand.class==subEntry.getValue()){
					Information si=new Information();
					si.setParentType(entry.getKey());
					si.setSubType(subEntry.getKey());
					si.setAddMethod("setPicker");
					subs.add(si);
				}
			}
			result.put("picker", subs);
		}
		
		if(Button.class==clz){
			List<Information> subs=new ArrayList<Information>();
			for(Map.Entry<String, Class<?>> subEntry:adaptorClass.entrySet()){
				if(Command.class.isAssignableFrom(subEntry.getValue())){
					Information si=new Information();
					si.setParentType(entry.getKey());
					si.setSubType(subEntry.getKey());
					si.setAddMethod("add");
					si.setSingle(true);
					subs.add(si);
				}
			}
			result.put("more", subs);
		}
		
		if(ConfirmCommand.class==clz){
			List<Information> subs=new ArrayList<Information>();
			for(Map.Entry<String, Class<?>> subEntry:adaptorClass.entrySet()){
				if(Command.class.isAssignableFrom(subEntry.getValue())){
					Information si=new Information();
					si.setParentType(entry.getKey());
					si.setSubType(subEntry.getKey());
					si.setAddMethod("setYes");
					si.setSingle(true);
					subs.add(si);
				}
			}
			result.put("yes", subs);
			subs=new ArrayList<Information>();
			for(Map.Entry<String, Class<?>> subEntry:adaptorClass.entrySet()){
				if(Command.class.isAssignableFrom(subEntry.getValue())){
					Information si=new Information();
					si.setParentType(entry.getKey());
					si.setSubType(subEntry.getKey());
					si.setAddMethod("setNo");
					si.setSingle(true);
					subs.add(si);
				}
			}
			result.put("no", subs);
		}
		
//		if(Checkboxgroup.class==clz){
//			
//			Information si=new Information();
//			si.setParentType(entry.getKey());
//			si.setSubType("Checkbox");
//			si.setAddMethod("add");
//			si.setSingle(false);
//			result.put("Checkbox", Arrays.asList(si));
//		}
//		if(Radiogroup.class==clz){
//			Information si=new Information();
//			si.setParentType(entry.getKey());
//			si.setSubType("Radio");
//			si.setAddMethod("add");
//			si.setSingle(false);
//			result.put("Radio", Arrays.asList(si));
//		}
		if(GridColumn.class==clz|| FieldsetLayout.class==clz || Img.class==clz||Leaf.class==clz){
			List<Information> subs=new ArrayList<Information>();
			for(Map.Entry<String, Class<?>> subEntry:adaptorClass.entrySet()){
				if(AbstractBox.class.isAssignableFrom(subEntry.getValue())){
					Information si=new Information();
					si.setParentType(entry.getKey());
					si.setSubType(subEntry.getKey());
					si.setAddMethod("setBox");
					si.setSingle(true);
					subs.add(si);
				}
			}
			result.put("box", subs);
		}
		if(AbstractBox.class.isAssignableFrom(clz)){
			Information si=new Information();
			si.setParentType(entry.getKey());
			si.setSubType("BoxField");
			si.setAddMethod("setField");
			si.setSingle(true);
			result.put("field", Arrays.asList(si));
		}
		if(GridPanel.class==clz||GridLayout.class==clz||TreePanel.class==clz){
			Information si=new Information();
			si.setParentType(entry.getKey());
			si.setSubType("Combofield");
			si.setAddMethod("setCombofield");
			si.setSingle(true);
			result.put("combofield", Arrays.asList(si));
		}
		if(Period.class==clz){
			Information si=new Information();
			si.setParentType(entry.getKey());
			si.setSubType("DatePicker");
			si.setAddMethod("setBegin");
			si.setSingle(true);
			result.put("begin", Arrays.asList(si));
			Information si2=new Information();
			si2.setParentType(entry.getKey());
			si2.setSubType("DatePicker");
			si2.setAddMethod("setEnd");
			si2.setSingle(true);
			result.put("end", Arrays.asList(si2));
		}

		if(result.size()>0){
			this.specialTypeMap.put(entry.getKey(), result);
		}
		}
		//添加额外的属性
//		if(AbstractBoxgroup.class.isAssignableFrom(parentClass)){
//			if((isCommonWidget(subClass)||Label.class==subClass||HorizontalGroup.class==subClass||VerticalGroup.class==subClass)&&
//					!(TemplateTitle.class==subClass||TemplateView.class==subClass)){
//				Information info=new Information();
//				info.setParentType(parentType);
//				info.setSubType(subType);
//				info.setAddMethod("addTarget");
//				return info;
//			}
//		}
		for(Map.Entry<String, Class<?>> entry:adaptorClass.entrySet()){
			Class<?> clz=entry.getValue();
			Map<String,List<Information>> result=new LinkedHashMap<String,List<Information>>();
			if(AbstractBoxgroup.class.isAssignableFrom(clz)){
				List<Information> subs=new ArrayList<Information>();
				for(Map.Entry<String, Class<?>> subentry:adaptorClass.entrySet()){
//					if(!isCommonWidget(subentry.getValue())){
//						continue;
//					}
					Class<?> subClass=subentry.getValue();
					if((isCommonWidget(subClass)||Label.class==subClass||HorizontalGroup.class==subClass||VerticalGroup.class==subClass)&&
							!(TemplateTitle.class==subClass||TemplateView.class==subClass)){
						Information si=new Information();
						si.setParentType(entry.getKey());
						si.setSubType(subentry.getKey());
						si.setAddMethod("addTarget");
						subs.add(si);
						}
				}
				result.put("target", subs);
				if(result.size()>0){
					this.otherTypeMap.put(entry.getKey(), result);
				}
			}
			if(AbstractUpload.class.isAssignableFrom(clz)){
				List<Information> subs=new ArrayList<Information>();
					Information si=new Information();
					si.setParentType(entry.getKey());
					si.setSubType("UploadButton");
					si.setAddMethod("addUpload_button");
					subs.add(si);
				result.put("upload_button", subs);
				if(result.size()>0){
					this.otherTypeMap.put(entry.getKey(), result);
				}
			}
			if(Validatable.class.isAssignableFrom(clz)){
				List<Information> subs=new ArrayList<Information>();
				for(Map.Entry<String, Class<?>> subentry:adaptorClass.entrySet()){
					if(Validate.class!=subentry.getValue()){
						continue;
					}
					Information info=new Information();
					info.setParentType(entry.getKey());
					info.setSubType(subentry.getKey());
					String[][] DATA = { { "name", "String", "T" ,"default"} };
					info.setAppendingProperies(makeAppendProps(DATA));
					info.setAddMethod("addValidate");
					subs.add(info);
				}
				result.put("validate", subs);
				if(result.size()>0){
					this.otherTypeMap.put(entry.getKey(), result);
				}
			} 
			if(GridLayout.class==clz||GridPanel.class==clz){
				List<Information> subs=new ArrayList<Information>();
				Information si=new Information();
				si.setParentType(entry.getKey());
				si.setSubType("GridColumn");
				si.setAddMethod("addColumn");
				subs.add(si);
				result.put("column", subs);
				if(result.size()>0){
					this.otherTypeMap.put(entry.getKey(), result);
				}
			}
			if(View.class==clz){
				List<Information> subs=new ArrayList<Information>();
				Information si=new Information();
				si.setParentType(entry.getKey());
				si.setSubType("DialogTemplate");
				si.setAddMethod("addTemplate");
				String[][] DATA = { { "id", "String", "T" } };
				si.setAppendingProperies(makeAppendProps(DATA));
				subs.add(si);
				result.put("template", subs);
				
				List<Information> subs2=new ArrayList<Information>();
				for(Map.Entry<String, Class<?>> subentry:adaptorClass.entrySet()){
					if(!Command.class.isAssignableFrom(subentry.getValue())){
						continue;
					}
					Information info=new Information();
					info.setParentType(entry.getKey());
					info.setSubType(subentry.getKey());
					String[][] DATA2 = { { "id", "String", "T" } };
					info.setAppendingProperies(makeAppendProps(DATA2));
					info.setAddMethod("addCommand");
					subs2.add(info);
				}
				result.put("command", subs2);
				if(result.size()>0){
					this.otherTypeMap.put(entry.getKey(), result);
				}
			}
			
//			if(DialogTemplate.class==subClass){//FIXME 放到other里面去
//				Information info=new Information();
//				info.setParentType(parentType);
//				info.setSubType(subType);
//				String[][] DATA = { { "id", "String", "T" } };
//				info.setAppendingProperies(makeAppendProps(DATA));
//				info.setAddMethod("addTemplate");
//				return info;
//			}
//			if(Command.class.isAssignableFrom(subClass)){//FIXME 放到other里面去
//				Information info=new Information();
//				info.setParentType(parentType);
//				info.setSubType(subType);
//				String[][] DATA = { { "id", "String", "T" } };
//				info.setAppendingProperies(makeAppendProps(DATA));
//				info.setAddMethod("addCommand");
//				return info;
//			}
		}
		
	}
	
	/**
	 * 取得默认的可支持的类型。
	 * @param type
	 * @return List
	 */
	public List<Information> getAcceptType(String type) {
		if(type==null||type.equals("")){//允许编辑器空的时候，增加View以及所有组件
//			ComponentRelation.Information info=new ComponentRelation.Information ();
//			info.setSubType("View");
//			info.setSingle(true);
//			return Arrays.asList(info);
//			List<Information> allInfo=subTypeMap.get("View");
//			allInfo.add(0, info);
//			return allInfo;
			type="View";
		}
		return subTypeMap.get(type);
	}
	
	/**
	 * 取得特殊可支持的类型。特殊的类型一般是唯一，并且ID是不能设置的。
	 * @param type
	 * @return Map
	 */
	public Map<String, List<Information>> getSpecialParts(String type) {
		return specialTypeMap.get(type);
	}
	
	/**
	 * 取得额外的可支持的类型。和默认可支持的不一样的地方主要表现在如下场景
	 * Checkboxgroup可以添加checkbox作为子节点。但他也可以额外的添加targets来标识这些checkbox绑定其他属性
	 * 这时候，我们就需要指定这些targets作为额外的子节点增加。他们添加方法一般不是add而是特定的方法。
	 * @param type
	 * @return Map
	 */
	public Map<String, List<Information>> getOtherType(String type) {
		return otherTypeMap.get(type);
	}
	
	/**
	 * 判断是否有包含关系，这个包含关系不包括特殊属性的判定，特殊属性判定使用另一套判定规则
	 * @param parentType String 父类名称
	 * @param parentClass Class 父类类型
	 * @param subType String 子类名称
	 * @param subClass Class 子类类型
	 * @return Information
	 */
	protected Information acceptInfo(String parentType, Class<?> parentClass, String subType, Class<?> subClass) {
		@SuppressWarnings("unchecked")
		List<Class<? extends AbstractWidget<?>>> hiddenClass=Arrays.asList(JsonTd.class,JsonGridLayout.class,
				JsonThead.class,JsonTr.class,ValueButton.class,
				UploadItem.class,EChartsPanel.class,Progress.class);
		if(hiddenClass.contains(subClass)){
			return  null;
		}
		if((isCommonLayout(parentClass)&&isCommonWidget(subClass))||//普通的layout和普通的widget之间有包含关系
				((Leaf.class==parentClass||TreePanel.class==parentClass)&&Leaf.class==subClass)||//树和树节点之间有包含关系
				((ButtonBar.class==parentClass||Button.class==parentClass||SubmitButton.class==parentClass||MenuCommand.class==parentClass)&&
						 (Button.class==subClass||SubmitButton.class==subClass||Split.class==subClass))||//按钮栏和按钮之间有包含关系
				(CommandContainer.class.isAssignableFrom(parentClass)&&Command.class.isAssignableFrom(subClass))||//CommandContainer 和Command 有包含关系
				(AlbumLayout.class==parentClass && Img.class==subClass)|| //AlbumLayout和Img有包含关系
				((GridLayout.class==parentClass||VerticalLayout.class==parentClass||HorizontalLayout.class==parentClass)&&
						 (TemplateTitle.class==subClass||TemplateView.class==subClass))||//仅允许基础布局，添加模板部件
				(Checkboxgroup.class==parentClass&&Checkbox.class==subClass)||//允许Checkboxgroup 添加Checkbox
				(Radiogroup.class==parentClass&&Radio.class==subClass)//允许Radiogroup 添加Radio
				){
			Information info=new Information();
			info.setParentType(parentType);
			info.setSubType(subType);
			info.setAddMethod("add");
			return info;
		}
//		if(Validatable.class.isAssignableFrom(parentClass)){
//			if(Validate.class==subClass){
//				Information info=new Information();
//				info.setParentType(parentType);
//				info.setSubType(subType);
//				String[][] DATA = { { "name", "String", "T" ,"default"} };
//				info.setAppendingProperies(makeAppendProps(DATA));
//				info.setAddMethod("addValidate");
//				return info;
//			}
//		}
		//FIXME  FormPanel GridLayout GridLayoutFormPanel Tr Validatable 
		//FIXME single-- View Td DialogCommand ReplaceCommand DialogTemplate
		//FIXME appdingProperties--  Thead GridLayout GridLayoutFormPanel （without tr） View(with Command) Validatable
		//FIXME addMethod-- 
//		if((Checkboxgroup.class==parentClass&&Checkbox.class==subClass)||
//				(Radiogroup.class==parentClass&&Radio.class==subClass)){
//				Information info=new Information();
//				info.setParentType(parentType);
//				info.setSubType(subType);
//				String[][] DATA = { { "toNode", "Boolean", "F" } };
//				info.setAppendingProperies(makeAppendProps(DATA));
//				info.setAddMethod("add");
//				return info;
//		}
//		if(AbstractBoxgroup.class.isAssignableFrom(parentClass)){
//			if((isCommonWidget(subClass)||Label.class==subClass||HorizontalGroup.class==subClass||VerticalGroup.class==subClass)&&
//					!(TemplateTitle.class==subClass||TemplateView.class==subClass)){
//				Information info=new Information();
//				info.setParentType(parentType);
//				info.setSubType(subType);
//				info.setAddMethod("addTarget");
//				return info;
//			}
//		}
		if(FormPanel.class==parentClass){
			if(isCommonWidget(subClass)||Label.class==subClass||HorizontalGroup.class==subClass||VerticalGroup.class==subClass){
				Information info=new Information();
				info.setParentType(parentType);
				info.setSubType(subType);
				info.setAddMethod("add");
				return info;
			}
		}
		if(GridLayout.class==parentClass||Thead.class==parentClass){
			if(Tr.class==subClass){
				Information info=new Information();
				info.setParentType(parentType);
				info.setSubType(subType);
				info.setAddMethod("add");
				return info; 
			}
			
			if(AbstractTd.class==subClass||StringAdaptor.class==subClass||isCommonWidget(subClass)){
				Information info=new Information();
				info.setParentType(parentType);
				info.setSubType(subType);
				String[][] DATA = { { "fromRow", "Integer", "T" }, { "fromColumn", "Integer", "T" }, { "toRow", "Integer", "F" },
						{ "toColumn", "Integer", "F" }, };
				info.setAppendingProperies(makeAppendProps(DATA));
				info.setAddMethod("add");
				return info;
			}
		}
		
		if(GridLayoutFormPanel.class==parentClass){
			if(isCommonWidget(subClass)||Label.class==subClass||HorizontalGroup.class==subClass||VerticalGroup.class==subClass){
				Information info=new Information();
				info.setParentType(parentType);
				info.setSubType(subType);
				String[][] DATA = { { "fromRow", "Integer", "T" }, { "fromColumn", "Integer", "T" }, { "toRow", "Integer", "F" },
						{ "toColumn", "Integer", "F" }, };
				info.setAppendingProperies(makeAppendProps(DATA));
				info.setAddMethod("add");
				return info;
			}
		}
		if(FlexGrid.class==parentClass){
			if(isCommonWidget(subClass)||Label.class==subClass||HorizontalGroup.class==subClass||VerticalGroup.class==subClass){
				Information info=new Information();
				info.setParentType(parentType);
				info.setSubType(subType);
				String[][] DATA = { { "occupy", "Integer", "F" } };
				info.setAppendingProperies(makeAppendProps(DATA));
				info.setAddMethod("add");
				return info;
			}
		}
		if(Tr.class==parentClass){
			if(AbstractTd.class==subClass){
				Information info=new Information();
				info.setParentType(parentType);
				info.setSubType(subType);
				String[][] DATA = { { "key", "String", "T" }};
				info.setAppendingProperies(makeAppendProps(DATA));
				info.setAddMethod("setData");
				return info;
			}
		}
		
		if(TabPanel.class==parentClass || StackPanel.class==parentClass){
			if(isCommonWidget(subClass)){
				Information info=new Information();
				info.setParentType(parentType);
				info.setSubType(subType);
				String[][] DATA = { { "title", "String", "F" },{"icon","Img","F"},{"click","String","F"} };
				info.setAppendingProperies(makeAppendProps(DATA));
				info.setAddMethod("add");
				return info;
			}
		}
		
//		if(AbstractUpload.class.isAssignableFrom(parentClass)){
//			if(UploadButton.class==subClass){
//				Information info=new Information();
//				info.setParentType(parentType);
//				info.setSubType(subType);
//				info.setAddMethod("addValue_button");
//				return info;
//			}
//		}
		if(View.class==parentClass){
			if(isCommonWidget(subClass)){
				Information info=new Information();
				info.setParentType(parentType);
				info.setSubType(subType);
				info.setSingle(true);
				info.setAddMethod("setNode");
				return info;
			}
			
			
		}
		if(AbstractTd.class==parentClass||DialogCommand.class==parentClass||DialogTemplate.class==parentClass){
			if(isCommonWidget(subClass)){
				Information info=new Information();
				info.setParentType(parentType);
				info.setSubType(subType);
				info.setSingle(true);
				info.setAddMethod("setNode");
				return info;
			}
		}
		if(ReplaceCommand.class==parentClass){
			if(isCommonWidget(subClass)||Label.class==subClass||HorizontalGroup.class==subClass||VerticalGroup.class==subClass
					||Command.class.isAssignableFrom(subClass)){
				Information info=new Information();
				info.setParentType(parentType);
				info.setSubType(subType);
				info.setSingle(true);
				info.setAddMethod("setNode");
				return info;
			}
		}
		
		return null;
	}
	
	private boolean isCommonWidget(Class<?> clz) {
		if(!Widget.class.isAssignableFrom(clz)){
			return false;
		}
		if(Leaf.class==clz||
				Label.class==clz||HorizontalGroup.class==clz||VerticalGroup.class==clz||
				MenuCommand.class==clz||DialogCommand.class==clz||
				DialogTemplate.class==clz||TemplateTitle.class==clz||TemplateView.class==clz||
				Img.class==clz|| Tr.class==clz||AbstractTd.class==clz||GridLeaf.class==clz||Thead.class==clz||
				CalendarItem.class==clz||UploadButton.class==clz||ComboboxOption.class==clz||Hidden.class==clz){
			return false;
		}
		return true;
	}


	private boolean isCommonLayout(Class<?> clz) {
		if(!Layout.class.isAssignableFrom(clz)){
			return false;
		}
		if(AbstractBoxgroup.class.isAssignableFrom(clz)){
			return false;
		}
		if(Leaf.class==clz||TreePanel.class==clz||
				ButtonBar.class==clz||SubmitButton.class==clz||Button.class==clz||MenuCommand.class==clz||
				AlbumLayout.class==clz||View.class==clz||
				GridLayout.class==clz||FlexGrid.class==clz||Tr.class==clz||TabPanel.class==clz){
			return false;
		}
		return true;
	}
	

	private List<PropertyDefine> makeAppendProps(String[][] data) {
		List<PropertyDefine> result = new ArrayList<PropertyDefine>();
		for (String[] row : data) {
			PropertyDefine d = new PropertyDefine();
			result.add(d);
			d.setName(row[0]);
			d.setType(row[1]);
			if(row.length>2)
			d.setRequired("T".equals(row[2]));
			if(row.length>3)
				d.setDefaultValue(row[3]);
		}
		return result;
	}
	
	
	
	/**
	 * 这两个组件是包含的时候是否唯一的。
	 * 他们可以用 {@link #getAcceptType(String)}中的信息获得到。提供这个方法，只是为了调用的时候简化。
	 * @param parentType
	 * @param subType
	 * @return boolean
	 */
	public boolean acceptSingle(String parentType, String subType) {
		if(subType==null){
			return true;
		}
		List<Information> infos= this.getAcceptType(parentType);
		for(Information info:infos){
			if(subType.equals(info.getSubType())){
				return info.isSingle();
			}
		}
		return false;
	}
	/**
	 * 找到追加属性
	 * @param parentType String
	 * @param subType String
	 * @param mode String
	 * @return List
	 */
	public List<PropertyDefine> getAppendingProperies(String parentType, String subType,String mode ){
		List<ComponentRelation.Information> relations=null;
		if(Utils.isEmpty(mode)){
			relations=AdaptorManager.getInstance().getCompRelation().getAcceptType(parentType);
		}else if(mode.startsWith("<")){
			Map<String,List<ComponentRelation.Information>> map=AdaptorManager.getInstance().getCompRelation().getSpecialParts(parentType);
			String key=mode.substring(1,mode.length()-1);
			relations=map==null?null:map.get(key);
		}else if(mode.startsWith("[")){
			Map<String,List<ComponentRelation.Information>> map=AdaptorManager.getInstance().getCompRelation().getOtherType(parentType);
			String key=mode.substring(1,mode.length()-1);
			relations=map==null?null:map.get(key);
		}
		if(relations!=null)
		for(ComponentRelation.Information info:relations){
			if(subType.equals(info.getSubType())){
				return info.getAppendingProperies();
			}
		}
		return null;
	}
}
